{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# NetworKit Visualization Tutorial"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "The vizbridges module provides the `widgetFromGraph` function, which creates and returns Python widgets for graph visualization. Per default, a graph is plotted in 2D using the Python-package `ipycytoscape`. If the parameter `dimension` to 3D, the graph network is plotted in 3D using `plotly`. For this to work one or both of the packages have to be installed on the machine, where the Jupyter backend is running. The default mode is 2D.\n",
    "There is an optional parameter for node scores **or** a partition list (e.g. as a result of from centrality or community detection algorithms). If provided the nodes are colored according to their partition membership or score."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Visualize in 2D using Cytoscape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When plotting a graph in 2D with Cytoscape, the internal layouting algorithm from Cytoscape is used. This and the performance of the plugin makes this visualization suitable for graphs with up to around 500 nodes. For larger graphs, it is recommended to use the 3D visualization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import networkit as nk\n",
    "from networkit import vizbridges\n",
    "\n",
    "# Read graph\n",
    "G = nk.readGraph(\"../input/karate.graph\", nk.Format.METIS)\n",
    "# Initalize and run Betweenness algorithm\n",
    "btwn = nk.centrality.Betweenness(G)\n",
    "btwn.run()\n",
    "\n",
    "# Visualize the karate graph with Betweenness scores\n",
    "nk.vizbridges.widgetFromGraph(G, nodeScores = btwn.scores())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initalize and run PLM community detection algorithm\n",
    "plm = nk.community.PLM(G)\n",
    "plm.run()\n",
    "\n",
    "# Visualize the karate graph with community detection\n",
    "nk.vizbridges.widgetFromGraph(G, nodePartition = plm.getPartition())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Visualize in 3D using Plotly"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When plotting a graph in 3D with Plotly, the Maxent-Stress layouting from networkit.viz.MaxentStress is used. With a moderate to decent client, graph visualizations with up to 50k of nodes are possible. Note: The time it takes for generating the widget scales with the number of nodes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Read graph\n",
    "G = nk.readGraph(\"../input/karate.graph\", nk.Format.METIS)\n",
    "# Initalize and run Betweenness algorithm\n",
    "btwn = nk.centrality.Betweenness(G)\n",
    "btwn.run()\n",
    "\n",
    "# Visualize the karate graph with Betweenness scores\n",
    "nk.vizbridges.widgetFromGraph(G, dimension = nk.vizbridges.Dimension.Three, nodeScores = btwn.scores())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initalize and run PLM community detection algorithm\n",
    "plm = nk.community.PLM(G)\n",
    "plm.run()\n",
    "\n",
    "# Visualize the power graph with community detection\n",
    "nk.vizbridges.widgetFromGraph(G, dimension = nk.vizbridges.Dimension.Three, nodePartition = plm.getPartition())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Visualize Edge Attributes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When plotting with Plotly (either 2D or 3D), there is the additional possibility of labeling the edges using `EdgeAttributes` as descriped in the Graph.ipynb. The following provides an example use case. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "# Read graph\n",
    "G = nk.readGraph(\"../input/tiny_01.graph\", nk.Format.METIS)\n",
    "\n",
    "G.indexEdges()\n",
    "\n",
    "# Create new edge attributes named \"myFloat\" and \"myInt\"\n",
    "att1 = G.attachEdgeAttribute(\"myFloat\", float)\n",
    "att2 = G.attachEdgeAttribute(\"myInt\", int)\n",
    "\n",
    "# Assign some random values to each edge\n",
    "for u,v in G.iterEdges():\n",
    "    att1[u,v] = round(random.uniform(0., 1.),2)\n",
    "    att2[u,v] = random.randint(0, 10)\n",
    "\n",
    "# Visualize edge attributes in 2D    \n",
    "nk.vizbridges.widgetFromGraph(G, dimension = nk.vizbridges.Dimension.TwoForcePlotly, edgeAttributes=[(\"myFloat\", float), (\"myInt\", int)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Visualize edge attributes in 3D    \n",
    "nk.vizbridges.widgetFromGraph(G, dimension = nk.vizbridges.Dimension.Three, edgeAttributes=[(\"myFloat\", float), (\"myInt\", int)])"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
